home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
ABUSESRC.ZIP
/
AbuseSrc
/
imlib
/
palette.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-17
|
11KB
|
534 lines
#include "palette.hpp"
#include "image.hpp"
#include "macs.hpp"
#include "dos.h"
#include "video.hpp"
#include "filter.hpp"
#include "jmalloc.hpp"
#include <math.h>
palette *lastl=NULL;
palette::palette(bFILE *fp)
{
ncolors=fp->read_short();
pal=(color *)jmalloc(sizeof(color)*ncolors,"palette");
usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
set_all_unused();
fp->read(pal,sizeof(color)*ncolors);
bg=0;
}
palette::palette(spec_entry *e, bFILE *fp)
{
fp->seek(e->offset,0);
ncolors=fp->read_short();
pal=(color *)jmalloc(sizeof(color)*ncolors,"palette");
usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
set_all_unused();
fp->read(pal,sizeof(color)*ncolors);
bg=0;
}
int palette::size()
{
return ncolors*sizeof(color)+2;
}
int palette::write(bFILE *fp)
{
fp->write_short(ncolors);
return fp->write(pal,sizeof(color)*ncolors)==ncolors;
}
int palette::find_closest(unsigned char r, unsigned char g, unsigned char b)
{
unsigned char *cl=(unsigned char *)addr();
int c=0,d=0x100000,i,nd;
for (i=0;i<256;i++)
{
nd=((int)r-(int)(*cl))*((int)r-(int)(*cl)); cl++;
nd+=((int)g-(int)(*cl))*((int)g-(int)(*cl)); cl++;
nd+=((int)b-(int)(*cl))*((int)b-(int)(*cl)); cl++;
if (nd<d)
{ c=i; d=nd; }
}
return c;
}
int palette::find_closest_non0(unsigned char r, unsigned char g, unsigned char b)
{
unsigned char *cl=(unsigned char *)addr()+3;
int c=1,d=0x7fffffff,i,nd;
for (i=1;i<256;i++)
{
nd=((int)r-(int)(*cl))*((int)r-(int)(*cl)); cl++;
nd+=((int)g-(int)(*cl))*((int)g-(int)(*cl)); cl++;
nd+=((int)b-(int)(*cl))*((int)b-(int)(*cl)); cl++;
if (nd<d)
{ c=i; d=nd; }
}
return c;
}
int palette::find_color(unsigned char r, unsigned char g, unsigned char b)
{
int i,ub,mask,find;
for (i=0,ub=0,mask=128,find=-1;i<ncolors && find<0;i++)
{
if (usd[ub]&mask)
if (r==pal[i].red && b==pal[i].blue && g==pal[i].green)
find=i;
mask>>=1;
if (mask==0)
{ mask=128; ub++; }
}
return find;
}
long palette::getquad(int x)
{ char entry[4];
entry[3]=0;
entry[2]=pal[x].red;
entry[1]=pal[x].green;
entry[0]=pal[x].blue;
return *((long *)entry);
}
void palette::black_white()
{
int i;
unsigned char r,g,b,gr;
for (i=0;i<256;i++)
{
get(i,r,g,b);
gr=(unsigned char)((double) r*0.30+(double) g*0.59+(double)b*0.11);
set(i,gr,gr,gr);
}
}
void palette::make_black_white()
{
int i,c;
set(0,0,0,0);
for (i=1;i<ncolors;i++)
{ c=(int)((double)i/(double)ncolors*(double)255);
set(i,c,c,c);
}
}
void palette::set_rgbs()
{
int i,v;
CHECK(ncolors==256);
for (i=0;i<64;i++)
{
if (i==0) v=0;
else
{
v=(int) ((double)i+(double)(sqrt(63-i)));
v<<=2;
}
set(i, i, 0, 0); // reds 0-63
set(i+64, 0, i, 0);
set(i+128, 0, 0, i); // blues 128-191
set(i+128+64, v, v, v); // whites .. rest
}
set_all_used();
}
void palette::set_all_used()
{
int i;
for (i=0;i<ncolors;i++) set_used(i);
}
void palette::set_all_unused()
{
int i;
for (i=0;i<ncolors;i++) set_unused(i);
}
palette *palette::copy()
{
palette *p;
int i;
p=new palette(ncolors);
for (i=0;i<ncolors;i++)
{
if (used(i))
p->set_used(i);
else p->set_unused(i);
p->set(i,red(i),green(i),blue(i));
}
return p;
}
void palette::set_used(int color_num)
{
int x,b;
CHECK(color_num>=0 && color_num<ncolors);
x=color_num/8;
b=color_num%8;
usd[x]|=(128>>b);
}
void palette::set_unused(int color_num)
{
int x,b;
CHECK(color_num>=0 && color_num<ncolors);
x=color_num/8;
b=color_num%8;
usd[x]&=(0xff^(128>>b));
}
int palette::used(int color_num)
{
int x,b;
CHECK(color_num>=0 && color_num<ncolors);
x=color_num/8;
b=color_num%8;
return (usd[x]&(128>>b));
}
int palette::add_color(unsigned int r, int unsigned g, int unsigned b, int closest_only)
{
int i,f,u,c;
if (!closest_only)
{
for (i=ncolors-1,f=-1,u=-1;i>=0 && f<0;i--)
{
if (used(i))
{
if (pal[i].red==r && pal[i].green==g && pal[i].blue==b)
f=i;
}
else
u=i;
}
} else { f=-1; u=-1; }
if (f<0)
{
if (u>=0)
{ pal[u].red=r;
pal[u].green=g;
pal[u].blue=b;
set_used(u);
f=u;
}
else
{
for (i=0,f=0,u=10000;i<ncolors;i++)
{ c=(pal[i].red-r)*(pal[i].red-r)+
(pal[i].green-g)*(pal[i].green-g)+
(pal[i].blue-b)*(pal[i].blue-b);
if (c<u)
{ f=i;
u=c;
}
}
}
}
return f;
}
void palette::defaults()
{
int i;
set(0,0,0,0);
set_used(0);
for (i=1;i<ncolors;i++)
set_unused(i);
if (ncolors==256)
for (i=0;i<ncolors;i++)
set(i,RED3(i),GREEN3(i),BLUE2(i));
else if (ncolors==16)
for (i=0;i<ncolors;i++)
set(i,255-i&3,255-(i&4)>>2,255-(i&8)>>3);
else
for (i=0;i<ncolors;i++)
set(i,255-i%3,255-(i+1)%3,255-(i+2)%3);
}
void palette::shift(int amount)
{
int i;
unsigned char m;
if (amount<0)
{
m=-amount;
for (i=0;i<ncolors*3;i++)
((unsigned char *) pal)[i]>>=m;
}
else if (amount>0)
{
m=amount;
for (i=0;i<ncolors*3;i++)
((unsigned char *) pal)[i]<<=m;
}
}
void palette::set(int x, unsigned char red, char unsigned green, char unsigned blue)
{ CONDITION(x>=0 && x<ncolors,"Pallete::set passed bad x");
CONDITION((int)red<=ncolors && (int)green<=ncolors && (int)blue<=ncolors,
"pallette::set color values bigger than palette");
pal[x].red=red; pal[x].green=green; pal[x].blue=blue;
}
void palette::get(int x, unsigned char &red, unsigned char &green, unsigned char &blue)
{ CONDITION(x>=0 && x<ncolors,"Pallete::get passed bad x");
red=pal[x].red; green=pal[x].green; blue=pal[x].blue;
}
palette::~palette()
{ if (pal) jfree(pal);
if (usd) jfree(usd);
}
palette::palette(int number_colors)
{
CONDITION(number_colors>0,"palette::constructor - need at least one color!");
ncolors=number_colors;
bg=0;
pal=(color *)jmalloc(ncolors*3,"palette");
usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
defaults();
}
quant_node::~quant_node()
{
/* if (!is_leaf())
{ for (i=0;i<8;i++)
if (children[i])
{ delete children[i];
children[i]=NULL;
}
} */
}
/*void quant_node::prune()
{
int t,r,g,b;
CONDITION(!is_leaf(),"Cannot prune a leaf!");
total(t,r,g,b);
red=r/t;
green=g/t;
blue=b/t;
be_childish();
} */
void quant_node::total(int &tnodes, int &tr, int &tg, int &tb)
{
int i;
if (is_leaf())
{ tnodes+=tot;
tr+=red*tot;
tg+=green*tot;
tb+=blue*tot;
}
else
{ for (i=0;i<8;i++)
if (children[i])
children[i]->total(tnodes,tr,tg,tb);
}
}
quant_node::quant_node(int level, quant_node *dad,
unsigned char r, unsigned char g, unsigned char b)
{
int i;
CONDITION(level<=8,"Tree cannot have more than eight levels");
if (level==8)
be_childish();
else
for (i=0;i<8;i++) children[i]=NULL;
padre=dad;
red=r; green=g; blue=b;
tot=0;
}
quant_palette::quant_palette(int max_colors)
{ root=NULL; nc=0; mx=max_colors; }
void quant_palette::re_delete(quant_node *who, int lev) // removes all children from memory
{ int x; // and recurses down
if (who)
{
if (!who->is_leaf())
{ for (x=0;x<8;x++)
if (who->children[x])
{
CONDITION(lev<8,"Levl > 7");
re_delete(who->children[x],lev+1);
level[lev].unlink((linked_node *)who->children[x]);
delete who->children[x];
}
}
}
}
void quant_palette::prune()
{
int pruned,lev,x,r,g,b,t;
quant_node *p,*f;
for (pruned=0,lev=8;lev>1 && !pruned;lev--)
{
p=(quant_node *)level[lev-1].first();
if (p)
{ do
{
f=p->father();
for (x=0;x<8 && !pruned;x++)
if (f->children[x])
if (f->children[x]->next()!=p->next()) // if this son is not me!
pruned=1; // I have a brother! stop
p=(quant_node *)p->next();
} while ((linked_node *) p!=level[lev-1].first() && !pruned);
}
}
CONDITION(lev>0,"could not prune!");
t=0; r=0; g=0; b=0;
f->total(t,r,g,b);
if (t<=1)
{
t=0; r=0; g=0; b=0;
f->total(t,r,g,b);
}
CONDITION(t>1,"Should be more colors\n");
printf("%d Pruned at level %d, r=%d, g=%d, b=%d, total nodes off = %d\n",nc,
lev,r/t,g/t,b/t,t);
f->set(r/t,g/t,b/t);
nc-=t;
nc++;
re_delete(f,lev);
f->be_childish();
}
void quant_palette::add_color(unsigned char r, unsigned char g, unsigned char b)
{
quant_node **p,*fat;
int lev,cn,stop;
p=&root;
lev=0;
stop=0;
fat=NULL;
if (nc>=mx-1)
prune();
while (!stop)
{
lev++;
if (!(*p))
{
if (lev>2 && !fat)
printf("h");
(*p)=new quant_node(lev,fat);
level[lev-1].add_end((linked_node *)(*p));
}
if (!(*p)->is_leaf())
{
cn=((r&(256>>lev))!=0)<<2;
cn+=((g&(256>>lev))!=0)<<1;
cn+=((b&(256>>lev))!=0);
fat=(*p);
p=&((*p)->children[cn]);
} else stop=1;
}
(*p)->set(r,g,b);
if (!(*p)->tot)
nc++;
(*p)->tot++;
}
palette *quant_palette::create_pal()
{
palette *p;
int i,x;
quant_node *pn;
p=new palette(mx);
for (x=0,i=7;i>=0;i++)
for (pn=(quant_node *)level[i].first();
pn!=(quant_node *)level[i].first();pn=(quant_node *)pn->next())
if (pn->is_leaf())
p->set(x++,pn->red,pn->green,pn->blue);
return p;
}
quant_palette::~quant_palette()
{
if (root)
{
re_delete(root,1);
delete root;
}
}
unsigned char palette::brightest(int all)
{ unsigned char r,g,b,bri;
unsigned i;
long brv;
brv=0; bri=0;
for (i=0;i<ncolors;i++)
{ if (all || used(i))
{
get(i,r,g,b);
if ((long)r*(long)g*(long)b>brv)
{ brv=(long)r*(long)g*(long)b;
bri=i;
}
}
}
return bri;
}
unsigned char palette::darkest(int all, int noblack)
{ unsigned char r,g,b,bri;
unsigned i;
long brv,x;
brv=(long)258*(long)258*(long)258; bri=0;
for (i=0;i<ncolors;i++)
{ if (all || used(i))
{
get(i,r,g,b);
x=(long)r*(long)g*(long)b;
if (x<brv && (x || !noblack))
{ brv=(long)r*(long)g*(long)b;
bri=i;
}
}
}
return bri;
}
palette *last_loaded()
{ return lastl; }
void palette::fade_to(int total_fades, int fade_on, int dest_r, int dest_g, int dest_b)
{
unsigned char *sl=(unsigned char *)addr();
int i;
for (i=0;i<ncolors;i++)
{
*(sl++)=(( dest_r-(int)*sl)*fade_on/total_fades+*sl);
*(sl++)=(( dest_g-(int)*sl)*fade_on/total_fades+*sl);
*(sl++)=(( dest_b-(int)*sl)*fade_on/total_fades+*sl);
}
}